package com.xuhuan.practice.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.file.FileNameUtil;
import com.xuhuan.practice.properties.OSSMinioProperties;
import io.minio.CopyObjectArgs;
import io.minio.CopySource;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author: huan.xu
 * @create: 2023/12/23 15:33
 * @description: minio工具类
 **/
@Slf4j
public class MinioUtil {

  private static MinioClient minioClient;

  private static OSSMinioProperties ossMinioProperties;

  static {
    MinioUtil.minioClient = SpringContextUtil.getBean(MinioClient.class);
    MinioUtil.ossMinioProperties = SpringContextUtil.getBean(OSSMinioProperties.class);
  }

  /**
   * 上传文件到minio
   *
   * @param file
   */
  public static String putObject(MultipartFile file) {
    InputStream inputStream;
    try {
      inputStream = file.getInputStream();
    } catch (IOException e) {
      log.error("获取文件流失败,{}", ExceptionUtils.getStackTrace(e));
      throw new RuntimeException("上传文件到MinIO服务失败");
    }
    StringBuilder updateFilePath = new StringBuilder();
    updateFilePath.append("/")
        .append(LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN))
        .append("/").append(UUIDUtil.generateUUID()).append(".")
        .append(FileNameUtil.extName(file.getOriginalFilename()));
    putObject(updateFilePath.toString(), inputStream);
    return updateFilePath.toString();
  }

  /**
   * 上传文件到minio
   *
   * @param objectName  文件全路径
   * @param inputStream 文件流
   */
  public static void putObject(String objectName, InputStream inputStream) {
    try {
      minioClient.putObject(
          PutObjectArgs.builder()
              .bucket(ossMinioProperties.getMinioBucketName())
              .object(objectName)
              .stream(inputStream, inputStream.available(), -1L)
              .build()
      );
    } catch (Exception e) {
      log.error("上传文件到MinIO服务失败，当前bucketName: {}, objectName：{}",
          new Object[]{ossMinioProperties.getMinioBucketName(), objectName, e});
      log.error("上传文件到MinIO服务失败,{}", ExceptionUtils.getStackTrace(e));
      throw new RuntimeException("上传文件到MinIO服务失败");
    }
  }

  /**
   * 从minio获取文件流
   *
   * @param objectName
   * @return
   */
  public static InputStream getObject(String objectName) {
    try {
      return minioClient.getObject(
          GetObjectArgs.builder()
              .bucket(ossMinioProperties.getMinioBucketName())
              .object(objectName)
              .build()
      );
    } catch (Exception e) {
      log.error("从MinIO服务获取文件失败，当前bucketName: {}, objectName：{}",
          new Object[]{ossMinioProperties.getMinioBucketName(), objectName, e});
      log.error("从MinIO服务获取文件失败,{}", ExceptionUtils.getStackTrace(e));
      throw new RuntimeException("从MinIO服务获取文件失败");
    }
  }

  /**
   * 从MinIO服务复制文件
   *
   * @param sourceObjectName
   * @param targetObjectName
   * @return
   */
  public static void copyObject(String sourceObjectName, String targetObjectName) {
    try {
      CopySource copySource = CopySource.builder()
          .bucket(ossMinioProperties.getMinioBucketName())
          .object(sourceObjectName)
          .build();

      CopyObjectArgs copyObjectArgs = CopyObjectArgs.builder()
          .bucket(ossMinioProperties.getMinioBucketName())
          .source(copySource)
          .object(targetObjectName)
          .build();

      minioClient.copyObject(copyObjectArgs);
    } catch (Exception e) {
      log.error(
          "从MinIO服务复制文件失败，当前bucketName: {}, sourceObjectName：{}, targetObjectName: {}",
          new Object[]{ossMinioProperties.getMinioBucketName(), sourceObjectName,
              targetObjectName, e});
      log.error("从MinIO服务复制文件失败,{}", ExceptionUtils.getStackTrace(e));
      throw new RuntimeException("从MinIO服务复制文件失败");
    }
  }

  /**
   * 从MinIO服务删除文件
   *
   * @param objectName
   * @return
   */
  public static void removeObject(String objectName) {
    try {
      minioClient.removeObject(
          RemoveObjectArgs.builder()
              .bucket(ossMinioProperties.getMinioBucketName())
              .object(objectName)
              .build()
      );
    } catch (Exception e) {
      log.error("从MinIO服务删除文件失败，当前bucketName: {}, objectName：{}",
          new Object[]{ossMinioProperties.getMinioBucketName(), objectName, e});
      log.error("从MinIO服务删除文件失败,{}", ExceptionUtils.getStackTrace(e));
      throw new RuntimeException("从MinIO服务删除文件失败");
    }
  }


  /**
   * 从MinIO服务移动文件
   *
   * @param sourceObjectName
   * @param targetObjectName
   */
  public static void moveObject(String sourceObjectName, String targetObjectName) {
    try {
      copyObject(sourceObjectName, targetObjectName);
      removeObject(sourceObjectName);
    } catch (Exception e) {
      log.error(
          "从MinIO服务移动文件失败，当前bucketName: {}, sourceObjectName：{}, targetObjectName: {}",
          new Object[]{ossMinioProperties.getMinioBucketName(), sourceObjectName,
              targetObjectName, e});
      log.error("从MinIO服务移动文件失败,{}", ExceptionUtils.getStackTrace(e));
      throw new RuntimeException("从MinIO服务移动文件失败");
    }
  }
}
